from machine import Pin, PWM
import time
from IR import IRTransmitter


# 美的空调红外控制类，基于IRTransmitter
class IRMideaAC:
    # 常量定义
    kMideaTick = 80
    kMideaBitMarkTicks = 7
    kMideaBitMark = kMideaBitMarkTicks * kMideaTick
    kMideaOneSpaceTicks = 21
    kMideaOneSpace = kMideaOneSpaceTicks * kMideaTick
    kMideaZeroSpaceTicks = 7
    kMideaZeroSpace = kMideaZeroSpaceTicks * kMideaTick
    kMideaHdrMarkTicks = 56
    kMideaHdrMark = kMideaHdrMarkTicks * kMideaTick
    kMideaHdrSpaceTicks = 56
    kMideaHdrSpace = kMideaHdrSpaceTicks * kMideaTick
    kMideaMinGapTicks = kMideaHdrMarkTicks + kMideaZeroSpaceTicks + kMideaBitMarkTicks
    kMideaMinGap = kMideaMinGapTicks * kMideaTick
    kMideaTolerance = 30  # 百分比
    kMidea24MinGap = 13000  # 微秒

    # 模式常量
    kMideaACAuto = 0
    kMideaACCool = 1
    kMideaACHeat = 2
    kMideaACDry = 3
    kMideaACFan = 4

    # 风速常量
    kMideaACFanAuto = 0
    kMideaACFanLow = 1
    kMideaACFanMed = 2
    kMideaACFanHigh = 3

    # 温度范围常量
    kMideaACMinTempC = 16
    kMideaACMaxTempC = 30
    kMideaACMinTempF = 61
    kMideaACMaxTempF = 86

    # 传感器温度范围
    kMideaACMinSensorTempC = 16
    kMideaACMaxSensorTempC = 30
    kMideaACMinSensorTempF = 61
    kMideaACMaxSensorTempF = 86

    # 消息类型
    kMideaACTypeCommand = 0
    kMideaACTypeSpecial = 1
    kMideaACTypeFollow = 2

    # 特殊命令
    kMideaACToggleSwingV = 0xA1826F000062
    kMideaACToggleEcono = 0xA1826F400022
    kMideaACToggleTurbo = 0xA1826F200042
    kMideaACToggleLight = 0xA1826F100052
    kMideaACToggleSelfClean = 0xA1826F8000E2
    kMideaACToggle8CHeat = 0xA1826F08006A
    kMideaACQuietOn = 0xA1826F040066
    kMideaACQuietOff = 0xA1826F050065

    # 其他常量
    kMideaBits = 56
    kMidea24Bits = 24
    kMideaACSensorTempOnTimerOff = 0x00
    kMideaACTimerOff = 0xFF

    def __init__(self, pin=15):
        # 初始化红外发射器，使用美的协议的时序参数
        self.ir = IRTransmitter(
            bit_mark=self.kMideaBitMark,
            bit1_space=self.kMideaOneSpace,
            bit0_space=self.kMideaZeroSpace,
            pin=pin
        )
        self.remote_state = 0xA1826FFFFF62  # 默认状态
        self.CleanToggle = False
        self.EconoToggle = False
        self._8CHeatToggle = False
        self.LightToggle = False
        self.Quiet = False
        self.Quiet_prev = False
        self.SwingVToggle = False
        self.TurboToggle = False
        self.KAYSUN_AC = False  # 默认为非KAYSUN型号
        if self.KAYSUN_AC:
            self.SwingVStep = False

    def _send_header(self):
        """发送协议头部"""
        self.ir.send_segment(self.kMideaHdrMark)
        time.sleep_us(self.kMideaHdrSpace)

    def _send_footer(self):
        """发送协议尾部"""
        self.ir.send_segment(self.kMideaBitMark)
        time.sleep_us(self.kMideaMinGap)

    def sendMidea(self, data, nbits, repeat=0):
        """发送美的协议数据"""
        if nbits % 8 != 0:
            return  # 位数必须是8的倍数

        # 发送指定次数
        for r in range(repeat + 1):
            # 协议先发送消息，然后发送完全反转的消息
            for inner_loop in range(2):
                # 发送头部
                self._send_header()

                # 发送数据
                for i in range(8, nbits + 1, 8):
                    segment = (data >> (nbits - i)) & 0xFF
                    self.ir.send_byte(segment)

                # 发送尾部
                self._send_footer()

                # 反转数据用于第二轮发送
                data = ~data & ((1 << nbits) - 1)  # 保持位数一致

            # 消息之间的间隙
            time.sleep_us(50000)  # 50ms间隙

    def send(self, repeat=0):
        """发送当前状态"""
        self.checksum()  # 确保发送前校验和正确
        self.sendMidea(self.remote_state, self.kMideaBits, repeat)

        # 处理各种特殊功能的切换
        if self.SwingVToggle:
            self.sendMidea(self.kMideaACToggleSwingV, self.kMideaBits, repeat)
            self.SwingVToggle = False

        if self.KAYSUN_AC and self.SwingVStep:
            self.sendMidea(0xA1826F02006C, self.kMideaBits, repeat)  # kMideaACSwingVStep
            self.SwingVStep = False

        if self.EconoToggle:
            self.sendMidea(self.kMideaACToggleEcono, self.kMideaBits, repeat)
            self.EconoToggle = False

        if self.TurboToggle:
            self.sendMidea(self.kMideaACToggleTurbo, self.kMideaBits, repeat)
            self.TurboToggle = False

        if self.LightToggle:
            self.sendMidea(self.kMideaACToggleLight, self.kMideaBits, repeat)
            self.LightToggle = False

        mode = self.getMode()
        if mode <= self.kMideaACAuto and self.CleanToggle:  # 仅在制冷、除湿或自动模式下
            self.sendMidea(self.kMideaACToggleSelfClean, self.kMideaBits, repeat)
            self.CleanToggle = False
        elif mode == self.kMideaACHeat and self._8CHeatToggle:  # 仅在制热模式下
            self.sendMidea(self.kMideaACToggle8CHeat, self.kMideaBits, repeat)
            self._8CHeatToggle = False

        if self.Quiet != self.Quiet_prev:
            cmd = self.kMideaACQuietOn if self.Quiet else self.kMideaACQuietOff
            self.sendMidea(cmd, self.kMideaBits, repeat)
            self.Quiet_prev = self.Quiet

    def stateReset(self):
        """重置状态到初始值"""
        self.remote_state = 0xA1826FFFFF62
        self.CleanToggle = False
        self.EconoToggle = False
        self._8CHeatToggle = False
        self.LightToggle = False
        self.Quiet = self.Quiet_prev = False
        self.SwingVToggle = False
        self.TurboToggle = False
        if self.KAYSUN_AC:
            self.SwingVStep = False

    def getRaw(self):
        """获取当前原始状态"""
        self.checksum()
        return self.remote_state

    def setRaw(self, newState):
        """设置原始状态"""
        self.remote_state = newState

    # 电源控制
    def on(self):
        self.setPower(True)

    def off(self):
        self.setPower(False)

    def setPower(self, on):
        # 从remote_state中设置电源位
        if on:
            self.remote_state |= 0x000000000100
        else:
            self.remote_state &= ~0x000000000100

    def getPower(self):
        return (self.remote_state & 0x000000000100) != 0

    # 温度单位控制
    def getUseCelsius(self):
        return (self.remote_state & 0x000000000200) == 0

    def setUseCelsius(self, on):
        current_temp = self.getTemp(self.getUseCelsius())
        if on:
            self.remote_state &= ~0x000000000200  # 摄氏度
        else:
            self.remote_state |= 0x000000000200  # 华氏度
        self.setTemp(current_temp, on)

    # 温度控制
    def setTemp(self, temp, useCelsius=True):
        if useCelsius:
            min_temp = self.kMideaACMinTempC
            max_temp = self.kMideaACMaxTempC
        else:
            min_temp = self.kMideaACMinTempF
            max_temp = self.kMideaACMaxTempF

        # 确保温度在有效范围内
        temp = max(min(temp, max_temp), min_temp)

        # 计算温度偏移值
        if useCelsius:
            temp_offset = temp - self.kMideaACMinTempC
        else:
            temp_offset = temp - self.kMideaACMinTempF

        # 更新状态中的温度位
        self.remote_state = (self.remote_state & ~0x00000000F000) | (temp_offset << 12)

    def getTemp(self, celsius=True):
        # 获取温度偏移值
        temp_offset = (self.remote_state >> 12) & 0x0F

        # 计算实际温度
        if celsius == self.getUseCelsius():
            if celsius:
                return temp_offset + self.kMideaACMinTempC
            else:
                return temp_offset + self.kMideaACMinTempF
        else:
            # 单位转换
            if celsius:
                return (temp_offset + self.kMideaACMinTempF - 32) * 5 // 9
            else:
                return (temp_offset + self.kMideaACMinTempC) * 9 // 5 + 32

    # 风扇速度控制
    def setFan(self, fan):
        fan = max(0, min(fan, self.kMideaACFanHigh))
        # 更新风扇位
        self.remote_state = (self.remote_state & ~0x000000030000) | (fan << 16)

    def getFan(self):
        return (self.remote_state >> 16) & 0x03

    # 模式控制
    def setMode(self, mode):
        valid_modes = [self.kMideaACAuto, self.kMideaACCool, self.kMideaACHeat,
                       self.kMideaACDry, self.kMideaACFan]
        if mode not in valid_modes:
            mode = self.kMideaACAuto
        # 更新模式位
        self.remote_state = (self.remote_state & ~0x0000000C0000) | (mode << 18)

    def getMode(self):
        return (self.remote_state >> 18) & 0x03

    # 睡眠模式控制
    def setSleep(self, on):
        if on:
            self.remote_state |= 0x000000100000
        else:
            self.remote_state &= ~0x000000100000

    def getSleep(self):
        return (self.remote_state & 0x000000100000) != 0

    # 其他功能控制方法
    def setSwingVToggle(self, on):
        self.SwingVToggle = on

    def setEconoToggle(self, on):
        self.EconoToggle = on

    def setTurboToggle(self, on):
        self.TurboToggle = on

    def setLightToggle(self, on):
        self.LightToggle = on

    def setCleanToggle(self, on):
        self.CleanToggle = on and self.getMode() <= self.kMideaACAuto

    def set8CHeatToggle(self, on):
        self._8CHeatToggle = on and self.getMode() == self.kMideaACHeat

    def setQuiet(self, on):
        self.Quiet = on

    # 校验和计算
    def calcChecksum(self, state):
        sum_val = 0
        temp_state = state

        for _ in range(5):
            temp_state >>= 8
            byte = temp_state & 0xFF
            # 反转字节的位
            reversed_byte = 0
            for i in range(8):
                reversed_byte = (reversed_byte << 1) | (byte & 1)
                byte >>= 1
            sum_val += reversed_byte

        sum_val = 256 - sum_val
        # 反转校验和的位
        reversed_sum = 0
        for i in range(8):
            reversed_sum = (reversed_sum << 1) | (sum_val & 1)
            sum_val >>= 1
        return reversed_sum

    def validChecksum(self, state):
        return (state & 0xFF) == self.calcChecksum(state)

    def checksum(self):
        # 更新校验和
        cs = self.calcChecksum(self.remote_state)
        self.remote_state = (self.remote_state & ~0xFF) | cs

    # 转换为字符串表示
    def __str__(self):
        power = "On" if self.getPower() else "Off"
        mode = ["Auto", "Cool", "Heat", "Dry", "Fan"][self.getMode()]
        temp = f"{self.getTemp()}C/{self.getTemp(False)}F"
        fan = ["Auto", "Low", "Medium", "High"][self.getFan()]
        celsius = "Celsius" if self.getUseCelsius() else "Fahrenheit"
        sleep = "On" if self.getSleep() else "Off"

        return (f"Midea AC: Power={power}, Mode={mode}, Temp={temp}, "
                f"Fan={fan}, Units={celsius}, Sleep={sleep}")


if __name__ == '__main__':
    # 初始化美的空调控制器，使用默认引脚15
    ac = IRMideaAC(pin=15)

    # 设置空调状态
    ac.on()
    ac.setMode(IRMideaAC.kMideaACCool)  # 制冷模式
    ac.setTemp(24)  # 24摄氏度
    ac.setFan(IRMideaAC.kMideaACFanMed)  # 中速风

    # 发送命令
    ac.send()

    # 发送摆动命令
    ac.setSwingVToggle(True)
    ac.send()

    # 关闭时释放资源
    # ac.ir.close()